﻿'TODO: Document LED8Segment
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Drawing.Drawing2D

Public Class LED8Segment
#Region "Defaults"
    Private def_NumDigits As Integer = 8
    Private def_SegmentThickness As Single = 3
    Private def_LEDValue As Double = -123.45
    Private def_Precision As Integer = 2
    Private def_LitColor As Color = Color.GreenYellow
    Private def_UnlitColor As Color = Color.Silver
    Private def_TruncateTrailingZeroes As Boolean = False
#End Region

#Region "Private Attributes"
    Private WithEvents _Background As New BackgroundType(Me)

    Private _SegmentThickness As Single = def_SegmentThickness
    Private _NumDigits As Integer = def_NumDigits
    Private _LEDValue As Double = def_LEDValue
    Private _Precision As Integer = def_Precision
    Private _LitColor As Color = def_LitColor
    Private _UnlitColor As Color = def_UnlitColor
    Private _TruncateTrailingZeroes As Boolean = def_TruncateTrailingZeroes
#End Region

#Region "Event Handlers"
    Private Sub _Background_PropertyChanged(ByVal PropertyName As String) Handles _Background.PropertyChanged
        Me.Invalidate()
    End Sub
#End Region

#Region "Hidden Properties"
    <Browsable(False)> _
    Shadows Property BackColor() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property ForeColor() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property BackgroundImage() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property BackgroundImageLayout() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property Text() As String
        Get
            Return Nothing
        End Get
        Set(ByVal value As String)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property RightToLeft() As Boolean
        Get

        End Get
        Set(ByVal value As Boolean)

        End Set
    End Property
    <Browsable(False)> _
    Shadows Property Font() As Font
        Get
            Return Nothing
        End Get
        Set(ByVal value As Font)

        End Set
    End Property
#End Region

#Region "Public Interface"
    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        SetTransparencyMode(False)

        Me.Size = New Size(200, 30)
        Me.Padding = New Padding(3, 1, 1, 1)
    End Sub

    <Category("Appearance"), TypeConverter(GetType(BackgroundTypeConverter))> _
   Public Property Background() As BackgroundType
        Get
            Return _Background
        End Get
        Set(ByVal value As BackgroundType)
            _Background = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetBackground()
        _Background.Reset()
    End Sub
    Public Function ShouldSerializeBackground() As Boolean
        Return _Background.ShouldSerialize()
    End Function

    <Category("Appearance"), Description("Determines the thickness of the LED segments.")> _
    Public Property SegmentThickness() As Single
        Get
            Return _SegmentThickness
        End Get
        Set(ByVal value As Single)
            If value < 1 Then
                Throw New Exception("SegmentThickness must be a positive number greater or equal to 1.")
            Else
                _SegmentThickness = value
                Me.Invalidate()
            End If
        End Set
    End Property
    Public Sub ResetSegmentThickness()
        SegmentThickness = def_SegmentThickness
    End Sub
    Public Function ShouldSerializeSegmentThickness() As Boolean
        Return Not (SegmentThickness.Equals(def_SegmentThickness))
    End Function

    <Category("Appearance"), Description("Determines the color of a ""lit"" LED segment.")> _
    Public Property LitColor() As Color
        Get
            Return _LitColor
        End Get
        Set(ByVal value As Color)
            _LitColor = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetLitColor()
        LitColor = def_LitColor
    End Sub
    Public Function ShouldSerializeLitColor() As Boolean
        Return Not (LitColor.Equals(def_LitColor))
    End Function

    <Category("Appearance"), Description("Determines the color of an ""unlit"" LED segment.")> _
    Public Property UnlitColor() As Color
        Get
            Return _UnlitColor
        End Get
        Set(ByVal value As Color)
            _UnlitColor = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetUnlitColor()
        UnlitColor = def_UnlitColor
    End Sub
    Public Function ShouldSerializeUnlitColor() As Boolean
        Return Not (UnlitColor.Equals(def_UnlitColor))
    End Function

    <Category("Gauge"), Description("Determines the total # of digits displayed.")> _
   Public Property NumDigits() As Integer
        Get
            Return _NumDigits
        End Get
        Set(ByVal value As Integer)
            If value <= 0 Then
                Throw New Exception("Number of digits must be a positive number.")
            Else
                _NumDigits = value
                Me.Invalidate()
            End If
        End Set
    End Property
    Public Sub ResetNumDigits()
        NumDigits = def_NumDigits
    End Sub
    Public Function ShouldSerializeNumDigits() As Boolean
        Return Not (NumDigits.Equals(def_NumDigits))
    End Function

    <Category("Gauge"), Description("Determines the precision of the gauge (# of digits to right of decimal pt).")> _
    Public Property Precision() As Integer
        Get
            Return _Precision
        End Get
        Set(ByVal value As Integer)
            If value < 0 Then
                Throw New Exception("Precision cannot be a negative number")
            Else
                _Precision = value
                Me.Invalidate()
            End If
        End Set
    End Property
    Public Sub ResetPrecision()
        Precision = def_Precision
    End Sub
    Public Function ShouldSerializePrecision() As Boolean
        Return Not (Precision.Equals(def_Precision))
    End Function

    <Category("Gauge"), Description("The value displayed on the gauge.")> _
    Public Property Value() As Double
        Get
            Return _LEDValue
        End Get
        Set(ByVal value As Double)
            _LEDValue = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetValue()
        Me.Value = def_LEDValue
    End Sub
    Public Function ShouldSerializeValue() As Boolean
        Return Not (Value.Equals(def_LEDValue))
    End Function


    <Category("Appearance"), Description("Indicates whether trailing zeroes after the decimal point should be removed or not.")> _
    Public Property TruncateTrailingZeroes() As Boolean
        Get
            Return _TruncateTrailingZeroes
        End Get
        Set(ByVal value As Boolean)
            _TruncateTrailingZeroes = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetTruncateTrailingZeroes()
        Me.TruncateTrailingZeroes = def_TruncateTrailingZeroes
    End Sub
    Public Function ShouldSerializeTruncateTrailingZeroes() As Boolean
        Return Not (TruncateTrailingZeroes.equals(def_TruncateTrailingZeroes))
    End Function



#End Region

#Region "Private Implementation"
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        'Add your custom paint code here

        Dim G As Graphics = e.Graphics
        Dim OuterBoundingRect As New RectangleF(Me.ClientRectangle.Y + Me.Padding.Left, Me.ClientRectangle.Y + Me.Padding.Top, _
                                           Me.ClientRectangle.Width - Me.Padding.Left - Me.Padding.Right, _
                                           Me.ClientRectangle.Height - Me.Padding.Top - Me.Padding.Bottom)


        'Find dimensions if each individual LED digit
        Dim Lw As Single
        Dim Lh As Single

        Lh = OuterBoundingRect.Height
        Lw = OuterBoundingRect.Width / (_NumDigits + 0.5!) 'leave 0.5 for negative sign

        'Fix Precision if Precision>NumDigits
        Dim ActualPrecision As Integer
        If Precision >= NumDigits Then
            ActualPrecision = NumDigits - 1
        Else
            ActualPrecision = Precision
        End If

        'Negative Sign Rectangle
        Dim NegBoundRect As New RectangleF(OuterBoundingRect.X, OuterBoundingRect.Y, Lw / 2, Lh)

        Dim IsNegative As Boolean = (Me.Value < 0)

        'Convert LEDValue to a string (truncate numbers to right of decimal place if needed)
        Dim FormatStr As String
        Dim ValueString As String

        If TruncateTrailingZeroes Then
            FormatStr = New String(CChar("#"), ActualPrecision)
            FormatStr = "0." & FormatStr
            ValueString = Format(Me.Value, FormatStr)

            'Remove any trailing zeroes
            If ValueString.Contains(".") Then
                While ValueString.Last = CChar("0")
                    ValueString = ValueString.Substring(0, ValueString.Length - 1)
                End While
            End If
        Else
            FormatStr = New String(CChar("0"), ActualPrecision)
            FormatStr = "0." & FormatStr
            ValueString = Format(Me.Value, FormatStr)
        End If

        'Remove any negative sign
        ValueString = ValueString.Replace("-", "")

        Dim DecimalPos As Integer = ValueString.IndexOf(".")
        Dim NumDigitsToLeft As Integer
        Dim NumDigitsToRight As Integer
        If DecimalPos > 0 Then
            NumDigitsToLeft = DecimalPos
            NumDigitsToRight = ValueString.Length - DecimalPos - 1
        Else
            NumDigitsToLeft = ValueString.Length
            NumDigitsToRight = 0
        End If


        Dim LEDDigits(_NumDigits) As LEDDigit
        For i = 0 To _NumDigits - 1
            Dim BoundingRect As New RectangleF(NegBoundRect.X + NegBoundRect.Width + (CSng(i) * Lw), OuterBoundingRect.Y, Lw, Lh)
            LEDDigits(i) = New LEDDigit(G, BoundingRect, _UnlitColor, _LitColor, _SegmentThickness)
            LEDDigits(i).LEDValue = Nothing
            LEDDigits(i).IsDecimalLit = False
        Next


        ValueString = ValueString.Replace(".", "")

        If ValueString.Length > _NumDigits Then
            'Overflow
            For i = 0 To _NumDigits - 1
                LEDDigits(i).LEDValue = 8
                LEDDigits(i).IsDecimalLit = True
            Next
            'Also draw negative sign
            DrawNegativeSign(G, NegBoundRect, _LitColor, _SegmentThickness)
        Else
            For i As Integer = 0 To ValueString.Length - 1
                Dim Digit As Integer = CInt(ValueString.Substring(ValueString.Length - i - 1, 1))

                If i = NumDigitsToRight AndAlso NumDigitsToRight > 0 Then
                    'Append Decimal pt to this digit
                    LEDDigits(_NumDigits - i - 1).IsDecimalLit = True
                Else
                    'Write out digit normally (no decimal point)
                    LEDDigits(_NumDigits - i - 1).IsDecimalLit = False
                End If
                LEDDigits(_NumDigits - i - 1).LEDValue = Digit
            Next

            'Next Draw Negative sign if applicable
            If IsNegative Then DrawNegativeSign(G, NegBoundRect, _LitColor, _SegmentThickness)
        End If

        For i = 0 To _NumDigits - 1
            LEDDigits(i).RenderLED()
        Next
    End Sub
    Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaintBackground(pevent)

        Dim myG As Graphics = pevent.Graphics
        'Draw Gauge background 
        If _Background.FillStyle = BackgroundType.FillStyles.Gradient Then
            Dim myBrush As LinearGradientBrush
            myBrush = New LinearGradientBrush(Me.ClientRectangle, _Background.BackColor1, _Background.BackColor2, Me._Background.FillGradientStyle)
            myG.FillRectangle(myBrush, Me.ClientRectangle)
        Else
            myG.FillRectangle(New SolidBrush(_Background.BackColor1), Me.ClientRectangle)
        End If
    End Sub

    Private Class LEDDigit
        Private def_SegmentGap As Single = 1

        Private _G As Graphics
        Private _OuterBoundingRect As RectangleF

        Private _Segments As New Dictionary(Of String, Boolean)

        Friend Sub New(ByRef G As Graphics, ByVal OuterBoundingRect As RectangleF, ByVal UnlitColor As Color, ByVal LitColor As Color, ByVal SegmentThickness As Single)
            _G = G
            _OuterBoundingRect = OuterBoundingRect
            _UnlitColor = UnlitColor
            _LitColor = LitColor
            _SegmentThickness = SegmentThickness

            _Segments.Add("A", False)
            _Segments.Add("B", False)
            _Segments.Add("C", False)
            _Segments.Add("D", False)
            _Segments.Add("E", False)
            _Segments.Add("F", False)
            _Segments.Add("G", False)
        End Sub


        Private _Value As Integer?
        Friend Property LEDValue() As Integer?
            Get
                Return _Value
            End Get
            Set(ByVal value As Integer?)
                _Value = value

                'Set lit segments
                _Segments("A") = False
                _Segments("B") = False
                _Segments("C") = False
                _Segments("D") = False
                _Segments("E") = False
                _Segments("F") = False
                _Segments("G") = False

                If _Value.HasValue Then
                    Select Case value
                        Case 0
                            _Segments("A") = True
                            _Segments("C") = True
                            _Segments("D") = True
                            _Segments("E") = True
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 1
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 2
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("C") = True
                            _Segments("E") = True
                            _Segments("F") = True
                        Case 3
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("C") = True
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 4
                            _Segments("B") = True
                            _Segments("D") = True
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 5
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("C") = True
                            _Segments("D") = True
                            _Segments("G") = True
                        Case 6
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("C") = True
                            _Segments("D") = True
                            _Segments("E") = True
                            _Segments("G") = True
                        Case 7
                            _Segments("A") = True
                            _Segments("D") = True
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 8
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("C") = True
                            _Segments("D") = True
                            _Segments("E") = True
                            _Segments("F") = True
                            _Segments("G") = True
                        Case 9
                            _Segments("A") = True
                            _Segments("B") = True
                            _Segments("D") = True
                            _Segments("F") = True
                            _Segments("G") = True
                    End Select
                End If

                'Refresh drawing
            End Set
        End Property

        Private _IsDecimalLit As Boolean
        Friend Property IsDecimalLit() As Boolean
            Get
                Return _IsDecimalLit
            End Get
            Set(ByVal value As Boolean)
                _IsDecimalLit = value
            End Set
        End Property

        Private _UnlitColor As Color
        Friend Property UnlitColor() As Color
            Get
                Return _UnlitColor
            End Get
            Set(ByVal value As Color)
                _UnlitColor = value
            End Set
        End Property

        Private _LitColor As Color
        Friend Property LitColor() As Color
            Get
                Return _LitColor
            End Get
            Set(ByVal value As Color)
                _LitColor = value
            End Set
        End Property

        Private _SegmentThickness As Single
        Friend Property SegmentThickness() As Single
            Get
                Return _SegmentThickness
            End Get
            Set(ByVal value As Single)
                _SegmentThickness = value
            End Set
        End Property

        Friend Sub RenderLED()

            Dim DecimalSize As Single = _SegmentThickness
            If DecimalSize < 4 Then DecimalSize = 4

            Dim BoundingRect As New RectangleF(_OuterBoundingRect.X, _OuterBoundingRect.Y, _
                                               _OuterBoundingRect.Width - DecimalSize, _
                                               _OuterBoundingRect.Height)

            Dim Hg As Single = (BoundingRect.Height - 3 * _SegmentThickness) / 2
            Dim Wg As Single = BoundingRect.Width - 2 * _SegmentThickness



            Dim Offset As Single = _SegmentThickness / 2

            Dim RectA As RectangleF = New RectangleF(BoundingRect.X + Offset, BoundingRect.Y, BoundingRect.Width - _SegmentThickness, _SegmentThickness)
            Dim RectB As RectangleF = New RectangleF(RectA.X, RectA.Y + RectA.Height + Hg, RectA.Width, RectA.Height)
            Dim RectC As RectangleF = New RectangleF(RectA.X, RectB.Y + RectB.Height + Hg, RectA.Width, RectA.Height)

            Dim RectD As RectangleF = New RectangleF(BoundingRect.X, BoundingRect.Y + Offset, _SegmentThickness, Hg + _SegmentThickness)
            Dim RectE As RectangleF = New RectangleF(RectD.X, RectD.Y + RectD.Height, RectD.Width, RectD.Height)
            Dim RectF As RectangleF = New RectangleF(BoundingRect.X + _SegmentThickness + Wg, RectD.Y, RectD.Width, RectD.Height)
            Dim RectG As RectangleF = New RectangleF(RectF.X, RectF.Y + RectF.Height, RectF.Width, RectF.Height)

            Dim LitBrush As New SolidBrush(LitColor)
            Dim UnlitBrush As New SolidBrush(Color.FromArgb(100, UnlitColor.R, UnlitColor.G, UnlitColor.B)) 'Add transparency to unlit color

            DrawHSegment(_G, RectA, CType(IIf(_Segments.Item("A") = True, LitBrush, UnlitBrush), SolidBrush))
            DrawHSegment(_G, RectB, CType(IIf(_Segments.Item("B") = True, LitBrush, UnlitBrush), SolidBrush))
            DrawHSegment(_G, RectC, CType(IIf(_Segments.Item("C") = True, LitBrush, UnlitBrush), SolidBrush))

            DrawVSegment(_G, RectD, CType(IIf(_Segments.Item("D") = True, LitBrush, UnlitBrush), SolidBrush))
            DrawVSegment(_G, RectE, CType(IIf(_Segments.Item("E") = True, LitBrush, UnlitBrush), SolidBrush))
            DrawVSegment(_G, RectF, CType(IIf(_Segments.Item("F") = True, LitBrush, UnlitBrush), SolidBrush))
            DrawVSegment(_G, RectG, CType(IIf(_Segments.Item("G") = True, LitBrush, UnlitBrush), SolidBrush))

            'Draw decimal circle
            Dim DecimalRect As RectangleF = New RectangleF(_OuterBoundingRect.X + _OuterBoundingRect.Width - DecimalSize, _
                                                        _OuterBoundingRect.Y + _OuterBoundingRect.Height - DecimalSize, _
                                                        DecimalSize, _
                                                        DecimalSize)


            If IsDecimalLit Then
                _G.FillEllipse(LitBrush, DecimalRect)
            Else
                If UnlitColor <> Color.Transparent Then _G.FillEllipse(UnlitBrush, DecimalRect)
            End If

        End Sub

        Private Sub DrawHSegment(ByRef G As Graphics, ByVal BoundingRect As RectangleF, ByVal Brush As SolidBrush)
            If Brush.Color <> Color.Transparent Then
                Dim BRect As New RectangleF(BoundingRect.X + def_SegmentGap, BoundingRect.Y, BoundingRect.Width - def_SegmentGap * 2, BoundingRect.Height)

                Dim Xa As Single = BRect.X
                Dim Ya As Single = BRect.Y + BRect.Height / 2
                Dim Xb As Single = BRect.X + BRect.Height / 2
                Dim Yb As Single = BRect.Y
                Dim Xc As Single = BRect.X + BRect.Width - BRect.Height / 2
                Dim Yc As Single = BRect.Y
                Dim Xd As Single = BRect.X + BRect.Width
                Dim Yd As Single = BRect.Y + BRect.Height / 2
                Dim Xe As Single = BRect.X + BRect.Width - BRect.Height / 2
                Dim Ye As Single = BRect.Y + BRect.Height
                Dim Xf As Single = BRect.X + BRect.Height / 2
                Dim Yf As Single = BRect.Y + BRect.Height

                Dim pts As PointF() = {New PointF(Xa, Ya), New PointF(Xb, Yb), _
                                       New PointF(Xc, Yc), New PointF(Xd, Yd), _
                                       New PointF(Xe, Ye), New PointF(Xf, Yf)}


                Dim path As New System.Drawing.Drawing2D.GraphicsPath
                path.AddPolygon(pts)


                G.FillPath(Brush, path)
            End If
        End Sub

        Private Sub DrawVSegment(ByRef G As Graphics, ByVal BoundingRect As RectangleF, ByVal Brush As SolidBrush)
            If Brush.Color <> Color.Transparent Then
                Dim BRect As New RectangleF(BoundingRect.X, BoundingRect.Y + def_SegmentGap, BoundingRect.Width, BoundingRect.Height - def_SegmentGap * 2)

                Dim Xa As Single = BRect.X + BRect.Width / 2
                Dim Ya As Single = BRect.Y
                Dim Xb As Single = BRect.X + BRect.Width
                Dim Yb As Single = BRect.Y + BRect.Width / 2
                Dim Xc As Single = BRect.X + BRect.Width
                Dim Yc As Single = BRect.Y + BRect.Height - BRect.Width / 2
                Dim Xd As Single = BRect.X + BRect.Width / 2
                Dim Yd As Single = BRect.Y + BRect.Height
                Dim Xe As Single = BRect.X
                Dim Ye As Single = BRect.Y + BRect.Height - BRect.Width / 2
                Dim Xf As Single = BRect.X
                Dim Yf As Single = BRect.Y + BRect.Width / 2

                Dim pts As PointF() = {New PointF(Xa, Ya), New PointF(Xb, Yb), _
                                       New PointF(Xc, Yc), New PointF(Xd, Yd), _
                                       New PointF(Xe, Ye), New PointF(Xf, Yf)}


                Dim path As New System.Drawing.Drawing2D.GraphicsPath
                path.AddPolygon(pts)

                G.FillPath(Brush, path)
            End If
        End Sub
    End Class

    Private Sub DrawNegativeSign(ByRef G As Graphics, ByVal BoundRect As RectangleF, ByVal LitColor As Color, ByVal SegmentThickness As Single)
        Dim X As Single = BoundRect.X
        Dim Y As Single = BoundRect.Y + (BoundRect.Height - SegmentThickness) / 2
        Dim Height As Single = SegmentThickness
        Dim Width As Single = BoundRect.Width - 3

        G.FillRectangle(New SolidBrush(LitColor), New RectangleF(X, Y, Width, Height))
    End Sub
#End Region

#Region "Transparency Support"
    Private Const WS_EX_TRANSPARENT As Int16 = &H20

    Friend Sub SetTransparencyMode(ByVal IsOn As Boolean)
        If IsOn Then
            'Support transparency - turn off double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, False) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
            Me.SetStyle(ControlStyles.Opaque, True)
        Else
            'No transparency support - enable double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
            Me.SetStyle(ControlStyles.Opaque, False)
        End If
        If Me.Parent Is Nothing Then
            Me.Refresh()
        Else
            Me.Parent.Refresh()
        End If
    End Sub
    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or WS_EX_TRANSPARENT
            Return cp
        End Get
    End Property
#End Region

#Region "Background Type"
    Public Class BackgroundType
        'Defaults
        Private Const def_SupportTransparency As Boolean = False

        Private def_BackColor1 As Color = Color.SteelBlue
        Private def_BackColor2 As Color = Color.LightSteelBlue
        Private def_FillStyle As FillStyles = FillStyles.Gradient
        Private def_FillGradientStyle As LinearGradientMode = LinearGradientMode.Vertical


        'Private Properties
        Private _SupportTransparency As Boolean = def_SupportTransparency

        Private _BackColor1 As Color = def_BackColor1
        Private _BackColor2 As Color = def_BackColor2
        Private _FillStyle As FillStyles = def_FillStyle
        Private _GradientOrientation As LinearGradientMode = def_FillGradientStyle

        Private _ParentCtl As LED8Segment = Nothing


        'Enumerations
        Public Enum FillStyles As Integer
            Solid = 0
            Gradient = 1
        End Enum

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        'Public Interface
        Friend Sub New(ByVal Control As LED8Segment)
            _ParentCtl = Control
        End Sub

        ''' <summary>
        ''' Defines the Background color of the gauge when <see cref="FillStyle"/> is set to <see cref="FillStyles">Solid</see>. Otherwise is used as the first color
        ''' in a color gradient with the end color determined by the <see cref="BackColor2"/> property.
        ''' </summary>
        ''' <value>The Background color of the gauge or the start gradient color of background.</value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Description("The background color of the control. Primary color if FillStyle is set to Solid or gradient start color if FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor1() As Color
            Get
                Return _BackColor1
            End Get
            Set(ByVal value As Color)
                _BackColor1 = value
                If _BackColor1 = Color.Transparent AndAlso _FillStyle = FillStyles.Solid Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("BackColor1")
            End Set
        End Property
        ''' <summary>
        ''' Resets the <see>BarGauge.BackColor1</see> property.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub ResetBackColor1()
            BackColor1 = def_BackColor1
        End Sub
        ''' <summary>
        ''' Indicates whether the default value of the property has changed from it's default in design mode and needs to be serialized.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ShouldSerializeBackColor1() As Boolean
            Return Not (BackColor1.Equals(def_BackColor1))
        End Function

        <Description("The secondary color of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor2() As Color
            Get
                Return _BackColor2
            End Get
            Set(ByVal value As Color)
                _BackColor2 = value
                RaiseEvent PropertyChanged("BackColor2")
            End Set
        End Property
        Public Sub ResetBackColor2()
            BackColor2 = def_BackColor2
        End Sub
        Public Function ShouldSerializeBackColor2() As Boolean
            Return Not (BackColor2.Equals(def_BackColor2))
        End Function

        <Description("The FillStyle for the Background of this control."), _
                BrowsableAttribute(True)> _
        Public Property FillStyle() As FillStyles
            Get
                Return _FillStyle
            End Get
            Set(ByVal value As FillStyles)
                _FillStyle = value
                If _FillStyle = FillStyles.Solid AndAlso _BackColor1 = Color.Transparent Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("FillStyle")
            End Set
        End Property
        Public Sub ResetFillStyle()
            FillStyle = def_FillStyle
        End Sub
        Public Function ShouldSerializeFillStyle() As Boolean
            Return Not (FillStyle.Equals(def_FillStyle))
        End Function

        <Description("The gradient style of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property FillGradientStyle() As LinearGradientMode
            Get
                Return _GradientOrientation
            End Get
            Set(ByVal value As LinearGradientMode)
                _GradientOrientation = value
                RaiseEvent PropertyChanged("FillGradientStyle")
            End Set
        End Property
        Public Sub ResetFillGradientStyle()
            FillGradientStyle = def_FillGradientStyle
        End Sub
        Public Function ShouldSerializeFillGradientStyle() As Boolean
            Return Not (FillGradientStyle.Equals(def_FillGradientStyle))
        End Function

        Public Sub Reset()
            _BackColor1 = def_BackColor1
            _BackColor2 = def_BackColor2
            _FillStyle = def_FillStyle
            _GradientOrientation = def_FillGradientStyle

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _BackColor1.Equals(def_BackColor1) _
                    AndAlso _BackColor2.Equals(def_BackColor2) _
                    AndAlso _FillStyle.Equals(def_FillStyle) _
                    AndAlso _GradientOrientation.Equals(def_FillGradientStyle) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Background)"
        End Function
    End Class
    Public Class BackgroundTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(BackgroundType))
        End Function
    End Class
#End Region
End Class
